iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 17
0

中秋節!突然後悔沒有提早一點開賽,有些參賽者已經完賽了...

廢話不多說,直接進入主題吧!

讓我們可以選擇使用的資料庫

我們現在有支援 SQlite,接下來我們也要支援 Postgresql 的部分,但這時候問題就來了,應該要讓開發者可以選擇用那種資料庫才對?那這部分怎麼實作呢?我們隨便打開一個 Rails 專案看看,可以發現在專案底下,關於資料庫的設定應該會是在 config/database.yml 裡面

# config/database.yml

default: &default
  adapter: sqlite3
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  timeout: 5000
  
development:
  <<: *default
  database: db/development.sqlite3

所以透過 Rails 這樣的機制,我們大概可以猜到,應該是靠 Ruby 的 Std-lib YAML 來讀取檔案,那我們就來實作一個吧,首先我們在 just_do 簡單建立一個 database.yml 檔案

# just_do/config/database.yml

default:
  adapter: postgresql
development:
  database: just_do

透過這個檔案,我們告訴 Mavericks 我們要用 postgresql,並且要用 just_do 這個資料庫名稱,所以在這之間,要先安裝 PostgreSQL,安裝過程請參照官網,Mac 的話建議使用 homebrew 來進行套件管理

接著我們進入 postgresql

$ psql postgres

建立一個 just_do 的資料庫,語法如下

CREATE DATABASE just_do;

建立好資料庫以後,我們修改一下 mini_migration.rb,把原本的 sqlite 換掉

# just_do/mini_migration.rb

require 'pg'

conn = PG.connect(dbname: 'just_do')

conn.exec <<SQL
CREATE SEQUENCE users_id_seq START 1;
CREATE TABLE tasks(id bigint DEFAULT nextval('users_id_seq') PRIMARY KEY
,title character varying, content character varying);
SQL

因為我們現在開始用的是 postgresql,所以記得到 Gemfile 加上pg 這個套件,別忘了記得 bundle install

# Gemfile
gem 'pg'

然後執行 migration

$ bundle exec ruby mini_migration.rb

建立連線

有了資料庫以後,我們將要來建立基本的連線,因為接下來程式碼會越來越多,所以需要整理一下,我們先建立一個 data_record.rb 的檔案

# mavericks/lib/data_record.rb

require 'mavericks/support'
require_relative "./data_record/connection_adapter.rb"
require_relative "./data_record/persistence"
require_relative "./data_record/method"
require_relative "./data_record/base"

module Mavericks
  module DataRecord
  end
end

接下來建立一個 data_record/ 的資料夾,裡面會存放我們威力加強版的 Model,首先建立 base.rb

# mavericks/lib/data_record/base.rb

module Mavericks
  module DataRecord
    class Base
      include Persistence
      extend Method
    end
  end
end

includeextend 相信大家都不陌生,一個是載入 instance method,一個是載入 class method

persistence.rb 之後會用來處理 save 部分,現在可以先不用管他

# mavericks/lib/data_record/persistence.rb

module Mavericks
  module DataRecord
    module Persistence
    end
  end
end

接著建立 connection_adapter 來建立連線,利用 pg 這個套件寫好的 method,我們只要使用 connect 就可以輕鬆連到資料庫,另外 pg 也提供另一個方便的 method 叫 exec,可以用來執行 SQL 語法

# mavericks/lib/data_record/connection_adapter.rb

module Mavericks
  module DataRecord
    module ConnectionAdapter
      class PostgreSQLAdapter
        def initialize(dbname)
          require 'pg'
          @db = PG.connect(dbname: dbname)
        end

        def execute(sql)
          @db.exec(sql)
        end
      end
    end
  end
end

接著是 method.rb 部分

# mavericks/lib/data_record/method.rb

require 'yaml'

module Mavericks
  module DataRecord
    module Method
      def establish_connection
        raw = File.read('config/database.yml')
        database_config = YAML.safe_load(raw)
        case database_config['default']['adapter']
        when 'postgresql'
          @@connection = ConnectionAdapter::PostgreSQLAdapter.new(database_config['development']['database'])
        when 'sqlite'
          # sqlite connection
        end
      end

      def connection
        @@connection
      end

      def schema
        self.connection.execute("SELECT column_name FROM information_schema.columns
        WHERE table_name= '#{self.table_name}'").map{|m|  m["column_name"]}
      end

      def table_name
        singular_table_name = Mavericks.to_underscore name
        Mavericks.to_plural singular_table_name
      end
    end
  end
end

我們這裡建立了一個 class methodestablish_connection,用來建立資料庫連線,連線的設定是靠載入 config/database.yml 來決定,透過 YAML 的解析,我們可以拿到資料庫的資訊,選擇用哪一種方式來處理,schematable_name 相信大家已經不陌生之前實作 sqlite_model.rb 就有用到一樣觀念

比較特別的是我們將 new 出來的資料庫物件放到 @@connection 這個類別變數,讓之後繼承的 Model 也可以使用,例如像是 Task

測試連線看看吧!

一樣回到 jsut_do 來測試看看

# just_do/sqlite_test.rb

# 換成載入 data_record
require 'mavericks/data_record'

# 建立連線
Mavericks::DataRecord::Base.establish_connection

class Task < Mavericks::DataRecord::Base
end

# 看看能不能取得 shcema
puts Task.schema

如果最後有印出資料欄位,代表成功了!


上一篇
[DAY 16] 復刻 Rails - ORM-我說那個 Attribute 呢?
下一篇
[DAY 18] 復刻 Rails - class_eval
系列文
向 Rails 致敬!30天寫一個網頁框架,再拿來做一個 Todo List30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言